package com.ecp.workflow.service;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.ecp.dto.RecordDto;
import com.ecp.dto.RolesDto;
import com.ecp.util.WorkFlowData;
import com.ecp.workflow.feign.CustomerFeign;
import com.ecp.workflow.feign.UUMSFeign;
import lombok.AllArgsConstructor;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * @author ：xly
 * @date ：Created in 2025-01-09 10:22
 * @description：
 * @modified By：
 * @version: $
 */
@Service
@AllArgsConstructor
public class FlowAbleService {

    @Resource
    private ProcessEngine processEngine;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private UUMSFeign uumsFeign;
    @Resource
    private CustomerFeign customerFeign;
    @Resource
    private HistoryService historyService;


    // 启动流程

    /**
     * 如果流程过程中设计到非接受驳回其他条件的，自己将条件放在map中传进来
     *
     * @param XMLPath  xml文件路径 在common中存成常量
     * @param flowName 这个流程类型 如增加客户、下订单等
     * @param info     需要在流程中使用的参数，比如客户名称，订单编号等
     * @param rolesDto 角色dto，包括当前发起人信息，正常流程角色集合，跨区地址，跨区角色集合
     * @param map
     */
    public String startFlowAble(String XMLPath, String flowName, Map<String, Object> info, RolesDto rolesDto, Map<String, Object> map) {
        // 获取审批人
        Map<String, Object> assignees = getAssignees(rolesDto);
        // 部署流程
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource(XMLPath)
                .name(flowName)
                .deploy();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
        Map<String, Object> variables = new HashMap<>();
        variables.put("msg", JSON.toJSONString(info));
        variables.put("workFlowType", flowName);
        variables.putAll(assignees);
        if (map != null) {
            variables.putAll(map);
        }
        runtimeService.startProcessInstanceById(processDefinition.getId(), variables);
        return processDefinition.getId();
    }

    // 查询当前用户流程
    public List<WorkFlowData> queryUserFlow(String userName) {
        List<WorkFlowData> result = new ArrayList<>();
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee(userName)
                .list();
        for (Task task : list) {
            WorkFlowData workFlowData = new WorkFlowData();
            workFlowData.setTaskId(task.getId());
            workFlowData.setMsg(JSON.parseObject(runtimeService.getVariables(task.getExecutionId()).get("msg").toString(), Map.class));
            workFlowData.setType(runtimeService.getVariables(task.getExecutionId()).get("workFlowType").toString());
            if (runtimeService.getVariables(task.getExecutionId()).get("rejectReason") != null) {
                workFlowData.setRejectReason(runtimeService.getVariables(task.getExecutionId()).get("rejectReason").toString());
            }
            result.add(workFlowData);
        }
        return result;
    }


    // 流程接受
    public void acceptFlow(String taskId) {
        addRecord(taskId);
        Map<String, Object> isAcceptMap = new HashMap<>();
        isAcceptMap.put("isAccept", 1);
        taskService.complete(taskId, isAcceptMap);

    }

    // 流程拒绝
    public void rejectFlow(String taskId, String reason) {
        addRecord(taskId);
        Map<String, Object> isAcceptMap = new HashMap<>();
        isAcceptMap.put("isAccept", 0);
        if (StrUtil.isNotEmpty(reason)) {
            isAcceptMap.put("rejectReason", reason);
        }
        taskService.complete(taskId, isAcceptMap);

    }

    // 自定义接收规则
    public void completeFlow(String taskId, Map<String, Object> variables) {
        taskService.complete(taskId, variables);
    }


    // 获取审批人
    public Map<String, Object> getAssignees(RolesDto rolesDto) {
        return uumsFeign.distribute(rolesDto);
    }


    public void addRecord(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        RecordDto recordDto = new RecordDto();
        recordDto.setDeploymentId(task.getProcessDefinitionId());
        recordDto.setRecordOperation(task.getName());
        recordDto.setOperator(task.getAssignee());
        customerFeign.addRecord(recordDto);
    }


    public RecordDto getLocalOperator(String deploymentId) {
        if (StrUtil.isNotEmpty(deploymentId)) {
            RecordDto recordDto = new RecordDto();
            recordDto.setRecordOperation(taskService.createTaskQuery().processDefinitionId(deploymentId).singleResult().getName());
            recordDto.setOperator(taskService.createTaskQuery().processDefinitionId(deploymentId).singleResult().getAssignee());
            return recordDto;
        }
        return null;
    }


    public String genProcessDiagrams(String processDefinitionId) {
        String processId = taskService.createTaskQuery().processDefinitionId(processDefinitionId).singleResult().getProcessInstanceId();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (processInstance == null) {
            return null;
        }

        List<HistoricActivityInstance> historyProcess = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();

        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType();
            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
                flows.add(hi.getActivityId());
            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
                activityIds.add(hi.getActivityId());
            }
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
        for (Task task : tasks) {
            activityIds.add(task.getTaskDefinitionKey());
        }

        ProcessDiagramGenerator processDiagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
        InputStream inputStream = null;

        try {
            inputStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, "宋体", "宋体", "宋体", null, 1.0, true);
            byte[] bytes1 = IoUtil.readBytes(inputStream);
            String s = Base64.getEncoder().encodeToString(bytes1);
            return s;
        } catch (IORuntimeException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
